<!DOCTYPE html>
<html>

<head>
  <title>序列面孔情绪评估任务</title>
  <script src="jspsych-6.0.5/jspsych.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-image-button-response.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-survey-text.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-survey-html-form.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-call-function.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-html-keyboard-response.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-image-slider-response_noButton.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-image-keyboard-response.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-external-html.js"></script>
  <script src="sequential_task_functions.js"></script>
  <script src="jspsych-6.0.5/plugins/jspsych-vsl-grid-scene1.js"></script>
  <script src="jquery-3.3.1.min.js"></script>
  <link href="jspsych-6.0.5/css/jspsych.css" rel="stylesheet" type="text/css">
  </link>
</head>

<body bgcolor="#AAAAAA"></body>
<script>

  /* ************************************* */
  /* Set up jsPsych blocks - static */
  /* ************************************ */

  var taskNumber = 50; //实验trial数，必须是5的倍数
  var attentionCheckInterval = 5; //每间隔多少个trial出现一次注意力检查，检查次数为taskNumber/attentionCheckInterval
  var practiceNumber = 3;
  var facesPool = loadFacePool(51, 150); //预先加载图片
  var slideList = createSlideList(1, 6);//指导语图片的数量。(a,b)，将b改为实际使用的指导语图片数量
  var trial = 0; //Trial Counter
  var attentionStimulus = loadStimulus(2); //preload 2 images for attention check
  var Face = {}; //create Face dictionary to (1)record fixation time, (2)make face sample and scale have the same person and valence in every trial
  Face.facePool = []; //record face data
  Face.wordList = ['but', 'rock', 'sky', 'our', 'course', 'we', 'table', 'house', 'here', 'mouth', 'tree', 'hello']; //word list for attention check
  var imageTestDescription = attentionStimulus; //designed for the image test
  var falseAnswer = 0;
  var falseAllowance = 4;  // 允许注意力测试最多错误次数
  var repeatAlert = 0;
  var repeatAllowance = 3; //how many times they can get alerts before they are cicked out
  var faceNumberList = []
  var faceNumber = ''
  var faceList = []
  var curFace = ''
  var simulateList = []
  var pID = ''
  var pName = ''
  var pSex = ''
  var pAge = ''
  /******************************************/
  /* Set up Instructions */
  /******************************************/

  var partcipantInfo = {
    type: 'survey-html-form',
    preamble: '请填写以下信息',
    html: '<div style="max-width: 300px; margin: 30px auto 0 auto;">\
  <div style="display: flex; align-items: center; margin-bottom: 20px;">\
    <label for="id" style="flex: 1; text-align: right; margin-right: 10px;">ID:</label>\
    <input id="id" name="id" type="text" style="flex: 2; width: 100%;" placeholder="&nbsp请输入数字"/>\
  </div>\
  \
  <div style="display: flex; align-items: center; margin-bottom: 20px;">\
    <label for="name" style="flex: 1; text-align: right; margin-right: 10px;">姓名:</label>\
    <input id="name" name="name" type="text" style="flex: 2; width: 100%;" placeholder="&nbsp请输入拼音全拼"/>\
  </div>\
  \
  <div style="display: flex; align-items: center; margin-bottom: 20px;">\
    <label for="age" style="flex: 1; text-align: right; margin-right: 10px;">年龄:</label>\
    <input id="age" name="age" type="text" style="flex: 2; width: 100%;" placeholder="&nbsp请输入数字"/>\
  </div>\
  \
  <div style="display: flex; align-items: center; margin-bottom: 30px;">\
    <label for="gender" style="flex: 1; text-align: right; margin-right: 10px;">性别:</label>\
    <input id="gender" name="gender" type="text" style="flex: 2; width: 100%;" placeholder="&nbsp man or woman" />\
  </div>\
</div>',
    button_label: '继续',
    on_finish: function (data) {
      pId = data.response.id,
      pName = data.response.name,
      pSex = data.response.gender,
      pAge = data.response.age
    }
  };

  var instructions = {
    type: "image-button-response",
    stimulus: getNextSlide,
    choices: ['继续'],
    margin_vertical: '10px',
    data: { Name: 'instructions' }
  };

  /******************************************/
  /* Start Experiment - trial by trial */
  /******************************************/

  var consent = {
    type: 'external-html',
    url: "external_page.html",
    cont_btn: "start",
    check_fn: check_consent
  };

  var fixationGetFace = { //getting new fixation time and face
    type: 'html-keyboard-response',
    stimulus: '<p style="font-size: 56px;">+</p>',
    trial_duration: getTimeAndFace,  //random select fixation time
    data: { Name: 'fixations' }
  };

  //生成注视点
  var fixation = { //only get new fixation time without changing face - in one series of face, there're different fixation time
    type: 'html-keyboard-response',
    stimulus: '<p style="font-size: 56px;">+</p>',
    trial_duration: getFixationTime,  //random select fixation time
    data: { Name: 'fixation' }
  };

  //生成单张高强度面孔
  var highFace = {
    type: 'image-keyboard-response',
    stimulus: function () {
      curFace = getFaceSample(1)
      return curFace
    },
    trial_duration: 1000,  //修改点：单张面孔呈现时间，单位ms
    choices: jsPsych.NO_KEYS,
    data: function () {
      Name: 'singleFace',
        //add data of the single face to face pool
        Face.facePool.push(Face.singleFace)
    },
    on_finish: function () {
      curFace = curFace.substring(5, curFace.length - 4);
      faceList.push(curFace)
    }
  };

  //生成单张低强度面孔
  var lowFace = {
    type: 'image-keyboard-response',
    stimulus: function () {
      curFace = getFaceSample(0)
      return curFace
    },
    trial_duration: 1000,  //单张面孔呈现时间，单位ms
    choices: jsPsych.NO_KEYS,
    data: function () {
      Name: 'singleFace',
        //add data of the single face to face pool
        Face.facePool.push(Face.singleFace)
    },
    on_finish: function () {
      curFace = curFace.substring(5, curFace.length - 4);
      faceList.push(curFace)
    }
  };

  //呈现反应界面，同时收集数据，participants see a slider and asked to estimate the mean group emotion
  var response = {
    type: 'image-slider-response_noButton',
    stimulus: getScale,
    prompt: "<p>请你评估刚刚这个试次中看到的所有面孔的平均情绪强度（左右移动鼠标调整面孔情绪强度）</p>",
    step: 1,
    max: 50,
    start: 0,
    on_load: morphedScale,
    data: function () {
      trial = trial + 1;
      var stringFaceList = faceList.join(", ");
      return {
        Name: 'response',
        trial: trial,
        faceList: stringFaceList,
        faceNum: faceNumberList[trial - 1],
        faceIdentity: Face.personX,
        emotion: Face.emotionX,
        fixationTime: Face.fixationTime,
        face_1: (Face.emotionX + Face.singleFace),
        description: Face.description,
      }
    },
    on_finish: function () {
      faceList = []
    }
  };

  //注意力测试
  var askTypeWord = {
    type: 'survey-text',
    questions: function () { return [{ prompt: '请输入这个单词: ' + getWord().bold() + '  (注意字母大小写)' }] },
    button_label: '继续'
  };

  //注意力测试
  var attentionCheck = {
    timeline: [askTypeWord],
    loop_function: checkTyping
  };

  var connectSurvey = {
    type: 'image-button-response',
    stimulus: getNextSlide,
    choices: ['结束实验']
  };


  /* create experiment definition array */
  var collective_emotion_estimation = []; //display instructions
  collective_emotion_estimation.push(partcipantInfo);

  for (var i = 0; i < slideList.length - 2; i++) {
    collective_emotion_estimation.push(instructions)
  };
  collective_emotion_estimation.push(fixationGetFace, attentionCheck);//attention check before practice task

    //封装试次生成函数
    function getATrial() {
    //trial开始
    //trial逻辑：使用faceNumber生成一个等长的模拟数组，其中1的个数就是希望的高强度面孔的个数
    //然后遍历模拟数组，当值 = 1时，生成一张高强度面孔。
    faceNumber = getRandomInt(6, 16); //修改点：单个trial面孔数量范围
    faceNumberList.push(faceNumber)
    collective_emotion_estimation.push(fixationGetFace);
    var oneNum = 0
    for (var i = 0; i < faceNumber; i++) {
      if (oneNum < 3) {  //修改点：oneNum，控制一个trial中高强度面孔不超过三个
        simulateList.push(1)
        oneNum++;
      } else {  //除了高强度的，其余都生成低强度面孔
        simulateList.push(0)
      }
    }
    simulateList.shuffle()
    for (const v of simulateList) {
      if (v == 0) {
        collective_emotion_estimation.push(fixation, lowFace);
      } else if (v == 1) {
        collective_emotion_estimation.push(fixation, highFace);
      } else {
        alert('程序出错！')
      }
    }
    simulateList = []
    collective_emotion_estimation.push(response);
    //trial结束
  }

 //练习试次
  for (var i = 0; i < practiceNumber; i++) { 
  getATrial()
   };


  //过渡提示语
  collective_emotion_estimation.push(instructions); //开始正式任务

  //正式实验
  for (var i = 0; i < taskNumber / attentionCheckInterval; i++) {
    collective_emotion_estimation.push(fixation, attentionCheck); //正式实验之前的注意力测试
    getATrial()
    var k = 0;
    while (k < (attentionCheckInterval - 1)) {
      getATrial()
      k++;
    }
  };

  collective_emotion_estimation.push(connectSurvey);

  /******************************************/
  /*           run the study                */
  /******************************************/
  jsPsych.init({
    preload_images: slideList, facesPool, attentionStimulus,
    timeline: collective_emotion_estimation,
    on_finish: function (data) {
      jsPsych.data.get().localSave('csv', 'participant' + pId + pName + pSex + pAge +'.csv'); //save as csv file with id as file name
    }
  })


</script>

</html>